var log = function() {
	
	var log = true;	
		
	function info(msg) {
		if (typeof console != 'undefined' && log == true) {
			console.log(msg);
		}
	}
	
	return {
		info: info
	};
}();

var slidestreamId = '';

var sign = function() {
        
    var savePeriodical = null;
    var checkRefreshPeriodical = null;
    var width = null;
    var height = null;
    var slidePlugins = Array();
    var slidestreamPlugins = Array();
    var config = {};
    var initialized = false;
    var lastUpdateTime = 0;
    var title = null;
    
    function init(settings) {
    	
        config = {
            parent              : 'div#signContainer',
            baseUrl             : $('#baseUrl').val(),
            slideSelector       : '.bbceSlide',
            useScreenResolution : false,
            saveTimer           : 30,  // how often to push the plugin data back to the server
            checkRefreshTimer   : 10, // how often to check to see if the sign needs to be refreshed,
            manualView          : $('#manualView').val()
        };
        
        // allow overriding the default config
        $.extend(config, settings);
        
        if (config.useScreenResolution == true) {
        	
	        width  = screen.width;
	        height = screen.height;

        } else {
        	
        	width = $(window).width();
        	height = $(window).height();      	
        }
        
    	// set the container to be the resolution of the sign
        $(config.parent).css({
            width: width,
            height: height
        });
                        
        // this checks to see if the sign needs to be refreshed every x seconds
        refreshPeriodical = window.setInterval(checkRefresh, config.checkRefreshTimer * 1000);
        //savePeriodical = window.setInterval(save, config.saveTimer * 1000);
        
        initialized = true;
    }
    
    function isManualView() {
    	return (config.manualView === 'true') ? true : false;
    }
    
    function checkRefresh() {
    	 $.ajax({
             url: config.baseUrl + '/sign/get-last-update-timestamp?slidestreamId=' + slidestreamId + '&manual=' + isManualView(),
             type: 'GET',
             dataType: 'json',
             async: false,
             success: function(data, textStatus) {
    		 	
    		 	updateTime = parseInt(data.updateTimestamp, 10);
    		 	
    		 	if (updateTime > lastUpdateTime) {
    		 		refresh();
    		 	}
             }
    	 });
    }
    
    function refresh() {
    	cookie.create('lastSlideId', slideManager.getCurrentSlideIndex(), '7');
    	window.location.reload(true);
    }
    
    // @todo implement the save method if one is needed for any reason :-P
    function save() {
    	
    }
    
    function getWidth() {
        return width;
    }
    
    function getHeight() {
        return height;
    }
    
    /**
     * Load the slides after the sign has been initialized
     */
    function loadData() {
    	
    	if (!initialized) {
    		document.write('Sign not initialized');
    		return;
    	}
        
    	// check to see if there was a starting index from a forced refresh
    	var startSlideId = cookie.read('lastSlideId');    	
    	
    	// if we found a saved index, then erase the cookie
        if (startSlideId != null) {
        	cookie.erase('lastSlideId');
        }
    	
        // get all the entities for the slideshow
        $.ajax({
            url: config.baseUrl + '/sign/get-data?slidestreamId=' + slidestreamId,
            type: 'GET',
            dataType: 'json',
            async: false,
            success: function(data, textStatus) {
                $.each(data.slides, function(index, el) {
                                        
                    var newSlide = slide.createSlide(el);
                    
                    // add slide to array of slides
                    slideManager.addSlide(newSlide);
                    
                    // add slide to the DOM
                    addSlideToDom(newSlide);
                    
                    // if this slide index is the starting index from before
                    // our refresh, then we'll start on this slide index
                    if (startSlideId != null && newSlide.data('slideId') == startSlideId) {
                    	slideManager.setStartingIndex(index);
                    }
                });
                
                $.each(data.slidestreamPlugins, function(name, data) {
                
                	var plugin = getRegisteredSlidestreamPlugin(name);

                	if (plugin !== null) {
                		plugin.setup(data);
                	}
                });
                
                title = data.slidestreamInfo.title;
                lastUpdateTime = parseInt(data.slidestreamInfo.updateTimestamp, 10) || 0;
            }
        });
        
        var count = $('iframe').length;
        $(function() {
        	$('iframe').load(function() {
            count--;
            if (count == 0) {
            	run();
            }
          });
        });
        
    }
    
    function addSlideToDom(el) {
    	$(config.parent).append(el);
    }
    
    function run() {
    	slideManager.start();
    }
    
    function registerSlidePlugin(pluginObj) {
        slidePlugins.push(pluginObj);
    }
    
    function getRegisteredSlidePlugin(name) {
    	$.each(plugins, function(index, el) {
    		if (el.getName() == name) {
    			return el;
    		}
    	});
    	
    	return null;
    }
    
    function registerSlidestreamPlugin(pluginObj) {
    	slidestreamPlugins.push(pluginObj);
    }
       
    function getRegisteredSlidestreamPlugin(name) {
    	
    	var retVal = null;
    	
    	$.each(slidestreamPlugins, function(index, el) {
    		if (el.getName() == name) {
    			retVal = el;
    		}
    	});
    	
    	return retVal;
    }
    
    return {
    	init: init,
    	start: loadData,
    	getHeight: getHeight,
    	getWidth: getWidth,
    	registerSlidePlugin: registerSlidePlugin,
    	registerSlidestreamPlugin: registerSlidestreamPlugin,
    	getRegisteredSlidePlugin: getRegisteredSlidePlugin,
    	getRegisteredSlidestreamPlugin: getRegisteredSlidestreamPlugin,
    	refresh: refresh,
    	save: save
    };
    
}();

var slideManager = function() {
		
		var currentSlide = null;
		var currentSlideIndex = 0;
	    var allSlides = [];
		var timer = null;
		
		function addSlide(newSlide) {
			allSlides.push(newSlide);
		}
		
		// the starting index needs to be the slide before this slide so we can 
		// easily check if the starting slide shouldn't be displayed because 
		// of it's schedule
		function setStartingIndex(index) {
			
			currentSlideIndex = parseInt(index, 10);
			
			if (currentSlideIndex > 1) {
				currentSlideIndex--;
			} else {
				currentSlideIndex = allSlides.length - 1;
			}
		}
		
		// starts all the fun.  It'll just rotate to the "next" slide, which is really
		// the slide we want to start with.  But this allows it to check the schedule
		// for that slide itself.
		function start() {
			
			for (var i=0; i < allSlides.length; i++) {
				
				// run the slide's init method if it exists
		        if ($.isFunction(document.getElementById('slide' + $(allSlides[i]).data('slideId')).contentDocument.defaultView.init)) {
					document.getElementById('slide' + $(allSlides[i]).data('slideId')).contentDocument.defaultView.init();
				}
			}
			
			rotate();
		}
		
		function getCurrentSlide() {
			return allSlides[currentSlideIndex];
		}

		function getCurrentSlideIndex() {
			return currentSlideIndex;
		}
		
		function getCurrentSlideId() {
			return $(getCurrentSlide()).data('slideId');
		}
		
		function getNextSlide() {
			
			var nextIndex = getNextSlideIndex();
			
			return allSlides[nextIndex];
		}
		
		function getNextSlideIndex() {
			
			if (currentSlideIndex == allSlides.length-1) {
		        var nextIndex = 0;
		    } else {
		        nextIndex = currentSlideIndex+1;
		    }
					
			// handle wrapping the slide show as well as support the schedules
			// that might be set for the slide
			while (nextIndex != currentSlideIndex) {
				
				if ($.isFunction(schedulePlugin.shouldBeDisplayed)) {
					if (schedulePlugin.shouldBeDisplayed(allSlides[nextIndex])) {
						return nextIndex;
					}
				}
				
				if (nextIndex == allSlides.length-1) {
			        var nextIndex = 0;
			    } else {
			        nextIndex = nextIndex+1;
			    }
			}
			
			return nextIndex;
		}
		
		function rollCurrentSlide() {
			
			var nextIndex = getNextSlideIndex();			
			currentSlideIndex = nextIndex;
		}

		function rotate() {
			
			var tmpCurrentSlide = $(getCurrentSlide());
			
			var tmpNextSlide = $(getNextSlide());

			// if the next slide and the current slide are the same, and the
			// slide shouldn't be shown, we need to make sure it handles that
			var tmpCurrentSlideIndex = getCurrentSlideIndex();
			var tmpNextSlideIndex = getNextSlideIndex();
			
			if (tmpCurrentSlideIndex == tmpNextSlideIndex) {
				
				if ($.isFunction(schedulePlugin.shouldBeDisplayed)) {
					if (!schedulePlugin.shouldBeDisplayed(tmpNextSlide)) {
						tmpCurrentSlide.fadeOut();
						return;
					}
				}
			}
			
			// only fade out this slide if there's more than one slide
			if (allSlides.length > 1) {
				tmpCurrentSlide.fadeOut();
			}
					
			if ($.isFunction(document.getElementById('slide' + tmpCurrentSlide.data('slideId')).contentDocument.defaultView.onHide)) {
				document.getElementById('slide' + tmpCurrentSlide.data('slideId')).contentDocument.defaultView.onHide();
			}
			
			tmpNextSlide.fadeIn();
			
			if ($.isFunction(document.getElementById('slide' + tmpNextSlide.data('slideId')).contentDocument.defaultView.onShow)) {
				document.getElementById('slide' + tmpNextSlide.data('slideId')).contentDocument.defaultView.onShow();
			}
			
			rollCurrentSlide();
			
			wait();
		}
		
		function wait() {
			var time = getTimeout($(getCurrentSlide()));
			clearInterval(timer);
			timer = setInterval(rotate, time);
		}
		
		function getTimeout(el) {
	        
	        var elTime = $(el).data('displayLength');
	        return parseInt(elTime * 1000, 10);
	    }
	    
	    /*
	    function getFx(opts) {
	    	        
	        if ($.isFunction(transitionPlugin.getFx)) {
	            return transitionMod.getFx(allSlides[nextIndex]);
	        }
	    };*/
	    
	    return {
	    	addSlide             : addSlide,
	    	getCurrentSlideIndex : getCurrentSlideIndex,
	    	getCurrentSlideId    : getCurrentSlideId,
	    	setStartingIndex     : setStartingIndex,
	    	start                : start
	    };
}();

var slide = function() {
    
	var config = {};
	
    function init(settings) {
    
        config = {
            baseUrl: $('#baseUrl').val()
        };
    
        // allow overriding the default config
        $.extend(config, settings);
    }
    
    function createSlide(el) {
        
    	var displayUrl = config.baseUrl + 
                     '/sign/slide?slideId=' + el.data.slideId + 
                     '&bbceScreenWidth=' + sign.getWidth() + 
                     '&bbceScreenHeight=' + sign.getHeight();

        var newSlide = $('<iframe></iframe>')
                        .attr('width', sign.getWidth() + 'px')
                        .attr('height', sign.getHeight() + 'px')
                        .attr('scrolling', 'no')
                        .attr('id', 'slide' + el.data.slideId)
                        .attr('name', 'slide' + el.data.slideId)
                        .attr('src', displayUrl)
                        .css({
                                border: '0',
                                margin: '0',
                                padding: '0',
                                display: 'none'
                        })
                        .addClass('bbceSlide');
        
        newSlide.data('slideId', el.data.slideId);
        newSlide.data('title', el.data.title);
        newSlide.data('url', el.displayUrl);
        newSlide.data('displayLength', el.displayLength);
        
        // store the data for the slide plugins into the slide object itself 
        $.each(el.pluginData, function(name, data) {
        	newSlide.data(name, data);
        });
        
        return newSlide;
    }
    
    return {
    	init: init,
    	createSlide: createSlide
    };
}();

$(document).ready(function() {
    
    slidestreamId = $('input#slidestreamId').val();
    
    sign.init();
    slide.init();
    
    /**
     * Initialize the plugins we want to use
     */
    schedulePlugin.init();
    transitionPlugin.init();
    marqueePlugin.init();
   
    sign.start(); // start the sign
});


/**
 * Sets up the all the interaction for the schedule plugin
 */
var schedulePlugin = function() {
    
	var config = {};
	var pluginName = 'Schedule';
	
    function init(settings) {
    
        config = {
            baseUrl : $('#baseUrl').val(),
        };
        
        $.extend(config, settings);
        
        sign.registerSlidePlugin(this);
    }
    
    function getName() {
    	return pluginName;
    }
    
    function shouldBeDisplayed(slide) {
    	
        var data = $(slide).data(pluginName);
    
        var ts = Math.round(new Date().getTime() / 1000);
        
        if ((data.length === 0) || (ts >= parseInt(data.fromDt, 10) && ts <= parseInt(data.toDt, 10)) || (ts >= parseInt(data.fromDt, 10) && data.toDt == 0) || (data.fromDt == 0 && ts <= parseInt(data.toDt, 10))) {
            //log.info($(slide).data('title') + ' should be displayed');
            return true;
        }    
        
        //log.info($(slide).data('title') + ' should not be displayed');
        return false;
    }
    
    return {
    	init: init,
    	getName: getName,
    	shouldBeDisplayed: shouldBeDisplayed
    };
}();

/**
 * Sets up the transition plugin
 */
var transitionPlugin = function() {

	var config = {};
	var pluginName = 'Transition';
	
    function init(settings) {
    
        config = {
            baseUrl : $('#baseUrl').val(),
        };
        
        $.extend(config, settings);
        
        sign.registerSlidePlugin(this);
    }
    
    function getName() {
    	return pluginName;
    }
    
    function getFx(obj) {
        return $(obj).data(pluginName).transition;
    }
    
    return {
    	init: init,
    	getName: getName,
    	getFx: getFx
    };
}();

/**
 * Sets up the marquee plugin
 */
var marqueePlugin = function () {

	var config = {};
	var pluginName = 'Marquee';
	var $cont = null;
	var refreshPeriodical;
	var currentLines = [];
		
    function init(settings) {
    	
        config = {
            baseUrl      : $('#baseUrl').val(),
            contSelector : '#marqueeContainer',
            position     : 'bottom',
            fx           : 'scrollUp',
            bgColor      : '#000000',
            textColor    : '#FFFFFF',
            opacity      : '1',
            effect       : 'roll',
            type         : 'text',
            url          : '',
            text         : '',
            rssMode      : 'title', // title, titleSnippet, or snippet
            refreshFeedTimer : 300
        };
        
        $.extend(config, settings);
        
        $cont = $(config.contSelector);
        
        $cont.hide();
        
        sign.registerSlidestreamPlugin(this);
    }
    
    function getName() {
    	return pluginName;
    }
    
    function setup(data) {
    	
    	if (parseInt(data.enabled, 10) == 1) {
    		
    		if (data.type == 'rss') {
	    		// refresh the RSS feed every (x) minutes
	            refreshPeriodical = window.setInterval(refreshFeed, config.refreshFeedTimer * 1000);
    		}
    		
    		// Set the effect before setting the text so that we can
    		// setup the text the correct way based on the effect we need.
    		// We also need to make sure we set the text and all the stuff 
    		// before we start it.
    		
    		config.type = data.type;
    		config.url = data.url;
    		config.text = data.text;
    		config.rssMode = data.rssMode;
    		
    		setEffect(data.effect);
    		setPosition(data.position);
    		setBgColor(data.bgColor);
    		setTextColor(data.textColor);
    		setFontFamily(data.fontFamily);
    		setFontSize(data.fontSize);
    		setOpacity(data.opacity);
    		
    		setupText();
    	}
    }
    
    function refreshFeed() {
    	setupText();
    }
    
    function start() {
    	
    	if (config.effect == "crawl") {
    		
    		// we've tested to see if the browser is a webkit browser when we created
    		// the element.  So if it is, it'll use the webkit specific marquee CSS declarations.
    		// if it wasn't not, then it'll be handled by the marquee enhancement plugin because
    		// we made it a marquee tag instead of the div.
    		
    	} else {
	    	$cont.cycle({
	            fx: config.fx,
	            timeout: 5000,
	        });
    	}
    }
    
    function show() {
        $cont.slideDown();
    }
    
    function hide() {
        $cont.slideUp();
    }
        
    function setBgColor(color) {
    	if (color.substring(0,1) != "#") {
    		color = "#" + color;
    	}
    	$cont.css('backgroundColor', color);
    }
    
    function setTextColor(color) {
    	if (color.substring(0,1) != "#") {
    		color = "#" + color;
    	}
    	$cont.css('color', color);
    }
    
    function setFontFamily(fontFamily) {
    	
    	var defaultFonts = ['Arial', 'Courier', 'Helvetica', 'Verdana'];
    	                    
    	if ($.inArray(fontFamily, defaultFonts) == -1) {

    		var link = $('<link>');
    		link.attr({
    		        type: 'text/css',
    		        rel: 'stylesheet',
    		        href: 'http://fonts.googleapis.com/css?family=' + fontFamily
    		});
    		
    		$('head').append(link);
    	}
    	
    	$cont.css('font-family', fontFamily);
    }
    
    function setFontSize(size) {
    	
    	var size = size + 'px';
    	
    	$cont.css({
    		'font-size': size,
    		'line-height' : size,
    		'height' : size
    	});
    }
    
    function setOpacity(val) {
    	alphaVal = parseFloat(val); 
    	$cont.css('filter', 'alpha(opacity=' + (alphaVal * 100) + ')')
    	     .css('-moz-opacity', val)
    		 .css('-khtml-opacity', val)
    		 .css('opacity', val);
    }
    
    function setEffect(effect) {
    	config.effect = effect;
    }
    
    function setPosition(pos) {
    	
    	if (pos == 'bottom') {
        	$cont.css({
        			    'bottom'     : '0',
						'border-top' : '3px solid #000'
			         });
        	config.fx = 'scrollUp';
        } else {
        	$cont.css({
						'top'           : '0',
						'border-bottom' : '3px solid #000'
        	         });
        	config.fx = 'scrollDown';
        }
    }
    
    function setupText() {
    	
    	var lines = [];

    	if (config.type == 'text') {
    		lines = config.text.split("\n");
    		setupDom(lines);
    	} else if (config.type == 'rss') {    		
    		getRss(config.url, config.rssMode);
    	}
    }
    
    function setupDom(lines) {
    	
    	$(config.contSelector).empty();
    	
    	if (config.effect == "roll") {
	    	$.each(lines, function(index, el) {
	    		var div = $('<div />');
	    		div.html(el)
	    		   .addClass('marqueeMessage');
	    		
	    		$cont.append(div);
	    	});
    	} else {
    		
    		if ($.browser.webkit) {
    			var marqueeEl = $('<div>');
    		} else {
    			var marqueeEl = $('<marquee>');
    		}
    		
    		marqueeEl.attr({
    					behavior     : "scroll",
    					scrollamount : "3",
    					direction    : "left",
    					width        : "100%",
    					id			 : 'marqueePlugin'
    			      });
    		
    		marqueeEl.text(lines.join(' | '));
    		
    		$(config.contSelector).append(marqueeEl);
    	}
    	
    	start();
		show();
    }
    
    function getRss(url, mode) {
    	
    	var lines = [];
    	
    	var feed = new google.feeds.Feed(url);
    	
    	feed.load(function(result) {
    		if (!result.error) {
    			
    			for (var i = 0; i < result.feed.entries.length; i++) {
    				var entry = result.feed.entries[i];
    	          
    				var text = '';
   	    	   
	   	    	  	if (mode == 'snippet') {
	   	    	  		text = entry['contentSnippet'];
	   	    	  	} else if (mode == 'titleSnippet') {
	   	    	  		text = entry['title'];
	   	    	  		text += ': ' + entry['contentSnippet'];
	   	    	  	} else { // just title
	   	    	  		text = entry['title'];
	   	    	  	}
	   	     	   
	   	    	  	lines.push(text);
    			}
    		}
    		
    		setupDom(lines);
    	});
    }
    
    return {
    	init: init,
    	getName: getName,
    	setup: setup,
    	show: show,
    	hide: hide
    };
}();

/**
 * A cookie helper.  We'll use it primarily for determining what slide we were
 * just on when we need to refresh the sign.
 */
var cookie = function() {
		
	function create(name, value, days) {
		
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		} else {	
			var expires = "";
		}
		
		document.cookie = name+"="+value+expires+"; path=/";
	}

	function read(name) {
		var nameEq = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') {
			    c = c.substring(1,c.length);
			}
			
			if (c.indexOf(nameEq) == 0) {
				return c.substring(nameEq.length,c.length);
			}
		}
		return null;
	}

	function erase(name) {
		cookie.create(name, "", -1);
	}
	
	return {
		create: create,
		read: read,
		erase: erase
	};
}();


/**
 *  http://projects.allmarkedup.com/jquery_url_parser/
 */
jQuery.url=function(){var segments={};var parsed={};var options={url:window.location,strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};var parseUri=function(){str=decodeURI(options.url);var m=options.parser[options.strictMode?"strict":"loose"].exec(str);var uri={};var i=14;while(i--){uri[options.key[i]]=m[i]||""}uri[options.q.name]={};uri[options.key[12]].replace(options.q.parser,function($0,$1,$2){if($1){uri[options.q.name][$1]=$2}});return uri};var key=function(key){if(!parsed.length){setUp()}if(key=="base"){if(parsed.port!==null&&parsed.port!==""){return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/"}else{return parsed.protocol+"://"+parsed.host+"/"}}return(parsed[key]==="")?null:parsed[key]};var param=function(item){if(!parsed.length){setUp()}return(parsed.queryKey[item]===null)?null:parsed.queryKey[item]};var setUp=function(){parsed=parseUri();getSegments()};var getSegments=function(){var p=parsed.path;segments=[];segments=parsed.path.length==1?{}:(p.charAt(p.length-1)=="/"?p.substring(1,p.length-1):path=p.substring(1)).split("/")};return{setMode:function(mode){strictMode=mode=="strict"?true:false;return this},setUrl:function(newUri){options.url=newUri===undefined?window.location:newUri;setUp();return this},segment:function(pos){if(!parsed.length){setUp()}if(pos===undefined){return segments.length}return(segments[pos]===""||segments[pos]===undefined)?null:segments[pos]},attr:key,param:param}}();


jQuery.fn.compare = function(t) {
    if (this.length != t.length) { return false; }
    var a = this.sort(),
        b = t.sort();
    for (var i = 0; t[i]; i++) {
        if (a[i] !== b[i]) { 
                return false;
        }
    }
    return true;
};